#include <iostream>
#include <memory>
#include "httpServer.hpp"
#include "Util.hpp"
#include "daemon.hpp"

void Usage()
{
    std::cout << "Please enter the correct format: " << std::endl
              << "\t./httpServer [port]" << std::endl;
}

std::string httpService(std::string request, HttpServer *hsvr)
{
    HttpRequest hreq;
    HttpResponse hresp;
    std::string response;

    hreq.Deserialize(request);

    if (hreq.GetUrl() == "/shop.html")
    {
        std::string cookie;

        // request携带Cookie报头且Session存在, 无需重新登录, 直接访问/shop.html
        if (hreq.GetCookie(&cookie) && hsvr->CheckSession(cookie))
        {
            int n = Util::ReadFileContent(rootdir + "/shop.html", &hresp.GetBody());
            hresp.AddHeader("Content-Length", std::to_string(n));
            hresp.AddHeader("Content-Type", Util::GetTypeBySuffix(".html"));
        }

        // 两种情况需重新登录
        // 1.request不携带Cookie报头
        // 2.request携带Cookie报头但Session不存在(session是内存级的，关闭服务器，上次客户端保存的session就不存在了)
        else
        {
            // 重定向到登录模块
            hresp.AddHeader("Location", "/loginPage.html");
            hresp.SetStateCode(302);
        }
    }

    else if (hreq.GetUrl() == "/login")
    {
        // 搞一个新进程来专门负责登录模块，这个进程的url写在登录request的请求行中
        // Server进程接收客户端登录request，获取用户名和密码，通过进程间通信将用户名和密码传递给新进程，由新进程负责执行登录逻辑
        // 用户登录模块
        std::string body = hreq.GetBody();
        std::string username, passwd;
        Util::GetUsernamePasswd(body, &username, &passwd);
        if (Util::CheckUser(username, passwd, ups))
        {
            // 既然要用户登录，说明该用户session不存在于服务器中
            // 添加用户session
            srand(time(nullptr));
            uint32_t sessionID = rand() % 100;
            hsvr->AddSession(sessionID, Session(username, passwd, sessionID));
            std::string cookieStr = "sessionID=" + std::to_string(sessionID);
            cookieStr += "; Max-Age=9999";
            hresp.AddHeader("Set-Cookie", cookieStr);

            LogMessage(DEBUG, "add new session, sessionID: %d\n", sessionID);
            // 重定向到/shop.html
            hresp.AddHeader("Location", "/shop.html");
            hresp.SetStateCode(302);
        }
        else
        {
            hresp.AddHeader("Location", "/logErr.html");
            hresp.SetStateCode(302);
        }
    }

    else
    {
        int n = -1;
        do
        {
            // n>=0 表示请求中的url有效 读取一次就成功 循环只跑一次
            // n<0 表示请求中的url无效 修改响应状态码和请求url后 重新读取
            n = Util::ReadFileContent(rootdir + hreq.GetUrl(), &hresp.GetBody());
            if (n < 0)
            {
                switch (n)
                {
                case -1:
                    hresp.SetStateCode(404);
                    hreq.ChangUrl("/404_err.html");
                    break;
                case -2:
                    hresp.SetStateCode(500);
                    hreq.ChangUrl("/500_err.html");
                    break;
                }
                continue;
            }
            else
            {
                hresp.AddHeader("Content-Length", std::to_string(n));
                hresp.AddHeader("Content-Type", Util::GetTypeBySuffix(hreq.GetSuffix())); // 根据URL后缀判断资源类型
            }
        } while (n < 0);
    }

    hresp.Serialize(&response);
    return response;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage();
        exit(USAGE_ERR);
    }

    uint16_t svr_port = atoi(argv[1]);

    std::unique_ptr<HttpServer> usvr(new HttpServer(httpService, svr_port));
    usvr->Initial();
    // Daemon();
    usvr->Start();

    return 0;
}
